// GTY


#include "Player/AuraPlayerController.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "AuraGameplayTags.h"
#include "EnhancedInputSubsystems.h"
#include "NavigationPath.h"
#include "NavigationSystem.h"
#include "NiagaraFunctionLibrary.h"
#include "AbilitySystem/AuraAbilitySystemComponent.h"
#include "Actor/MagicCircle.h"
#include "auragame/auragame.h"
#include "Components/DecalComponent.h"
#include "Components/SplineComponent.h"
#include "Input/AuraInputComponent.h"
#include "Interaction/EnemyInterface.h"
#include "GameFramework/Character.h"
#include "UI/Widget/DamageTextComponent.h"

AAuraPlayerController::AAuraPlayerController()
{
	bReplicates = true;// 这是服务器将 input 发送到 Client 端所必需的

	Spline = CreateDefaultSubobject<USplineComponent>("Spline");// 创建一个 Spline 组件 初始化
	
}

void AAuraPlayerController::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	
	CursorTrace();// 处理鼠标追踪

	AutoRun();
	UpdateMagicCircleLocation();
	
}

void AAuraPlayerController::ShowMagicCircle(UMaterialInterface* DecalMaterial)
{
	if(!IsValid(MagicCircle))
	{
		MagicCircle = GetWorld()->SpawnActor<AMagicCircle>(MagicCircleClass);
	}

	//设置贴花材质
	if(DecalMaterial != nullptr)
	{
		MagicCircle->MagicCircleDecal->SetMaterial(0, DecalMaterial);
	}

}

void AAuraPlayerController::HideMagicCircle() const
{
	if(IsValid(MagicCircle))
	{
		MagicCircle->Destroy();
	}
}

void AAuraPlayerController::CursorTrace()
{
	//判断当前事件是否被阻挡，如果事件被阻挡，则清除相关内容
	if(GetASC() && GetASC()->HasMatchingGameplayTag(FAuraGameplayTags::Get().Player_Block_CursorTrace))
	{
		if(ThisActor) ThisActor->UnHighlightActor();
		if(LastActor) LastActor->UnHighlightActor();
		ThisActor = nullptr; 
		LastActor = nullptr;
		return;
	}

	const ECollisionChannel TraceChannel = IsValid(MagicCircle) ? ECC_ExcludePlayers : ECC_Visibility;
	
	GetHitResultUnderCursor(TraceChannel, false,CursorHit);
	// 获取鼠标追踪下的 hit 结果
	// //ECC_Visibility：指定碰撞通道为可见性通道。  false：表示不进行穿透检测。  CursorHit：用于存储碰撞结果的对象。

	if(!CursorHit.bBlockingHit)// 如果未发生碰撞，则返回
	{
		return;
	}

	LastActor = ThisActor;// 记录上一个 Actor
	ThisActor = Cast<IEnemyInterface>(CursorHit.GetActor());// 将 hit 结果转换为 IEnemyInterface

	if(ThisActor != LastActor)
	{
		if(ThisActor) ThisActor->HighlightActor();
		if(LastActor) LastActor->UnHighlightActor();
	}


}

void AAuraPlayerController::AbilityInputTagPressed(FGameplayTag InputTag)
{
	//判断当前事件是否被阻挡，如果事件被阻挡，则清除相关内容
	if(GetASC() && GetASC()->HasMatchingGameplayTag(FAuraGameplayTags::Get().Player_Block_InputPressed))
	{
		return;
	}
	
	if (InputTag.MatchesTagExact(FAuraGameplayTags::Get().InputTag_LMB))// 如果按下了左键
	{
		bTargeting = ThisActor ? true: false;
		bAutoRunning = false;
		FollowTime = 0.f;
	}
	if (GetASC())
	{
		GetASC()->AbilityInputTagPressed(InputTag);
	}
}

void AAuraPlayerController::AbilityInputTagReleased(FGameplayTag InputTag)
{
	//GEngine->AddOnScreenDebugMessage(2, 5.f, FColor::White, FString::Printf(TEXT("Released: %s"), *InputTag.ToString()));
	//处理判断抬起事件是否被阻挡
	if(GetASC() && GetASC()->HasMatchingGameplayTag(FAuraGameplayTags::Get().Player_Block_InputReleased))
	{
		return;
	}
	if ( !InputTag.MatchesTagExact(FAuraGameplayTags::Get().InputTag_LMB))// 如果按的 不是 左键
	{
		if (GetASC() )
		{
			GetASC()->AbilityInputTagReleased(InputTag);
		}
		return;
	}

	if (GetASC() )
	{
		GetASC()->AbilityInputTagReleased(InputTag);
	}
	
	if (!bTargeting && !bShiftKeyDown)
	{
		const APawn* ControlledPawn = GetPawn();
		if (FollowTime <= ShortPressThreshold)// 如果追踪时间小于等于短按阈值
		{
			//要使用此模块，我们需要在Build.cs里面将NavigationSystem加入(private)，然后编译的时候将会将此模块自动编入
			if(UNavigationPath* NavPath = UNavigationSystemV1::FindPathToLocationSynchronously(this,ControlledPawn->GetActorLocation(),CachedDestination))
			{
				Spline->ClearSplinePoints(false);// 清除 Spline 的所有点
				for(const FVector& PointLoc : NavPath->PathPoints)// 遍历路径点
				{
					Spline->AddSplinePoint(PointLoc, ESplineCoordinateSpace::World); //将新的位置添加到样条曲线中
					//DrawDebugSphere(GetWorld(), PointLoc, 8.f, 8, FColor::Orange, false, 5.f); //点击后debug调试
				}
				
				//自动寻路将最终目的地设置为导航的终点，方便停止导航
				if (NavPath->PathPoints.Num() > 0)
				{
					CachedDestination = NavPath->PathPoints[NavPath->PathPoints.Num() - 1];
				}
				
				bAutoRunning = true;// 自动运行
			}
			if (GetASC() && !GetASC()->HasMatchingGameplayTag(FAuraGameplayTags::Get().Player_Block_InputReleased))
			{
				UNiagaraFunctionLibrary::SpawnSystemAtLocation(this, ChickNiagaraSystem, CachedDestination);
			}
		}
		FollowTime = 0.f;
		bTargeting = false;
	}
	
}



void AAuraPlayerController::AbilityInputTagHeld(FGameplayTag InputTag)
{
	//GEngine->AddOnScreenDebugMessage(3, 5.f, FColor::White, FString::Printf(TEXT("Held: %s"), *InputTag.ToString()));	
	//通过标签阻止悬停事件的触发
	if(GetASC() && GetASC()->HasMatchingGameplayTag(FAuraGameplayTags::Get().Player_Block_InputHeld))
	{
		return;
	}
	if ( !InputTag.MatchesTagExact(FAuraGameplayTags::Get().InputTag_LMB))// 如果按的 不是 左键
	{
		if (GetASC() )
		{
			GetASC()->AbilityInputTagHeld(InputTag);
		}
		return;
	}

	if (bTargeting || bShiftKeyDown)
	{
		if (GetASC())
		{
			GetASC()->AbilityInputTagHeld(InputTag);
		}
	}
	else
	{
		FollowTime += GetWorld()->GetDeltaSeconds();// 增加追踪时间
		
		if (CursorHit.bBlockingHit)// 如果发生碰撞
		{
			CachedDestination = CursorHit.ImpactPoint;// 将命中点的 ImpactPoint 赋值给 CachedDestination
		}
		if(APawn* ControlledPawn = GetPawn())
		{
			const FVector WorldDirection = (CachedDestination - ControlledPawn->GetActorLocation()).GetSafeNormal();// 计算命中点与控制器位置之间的向量
			ControlledPawn->AddMovementInput(WorldDirection);// 将命中点与控制器位置之间的向量添加到控制器的移动输入中
		}


	}
	///
	
}

UAuraAbilitySystemComponent* AAuraPlayerController::GetASC()
{
	if (AuraAbilitySystemComponent == nullptr)
	{
		AuraAbilitySystemComponent = Cast<UAuraAbilitySystemComponent>(UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(GetPawn<APawn>()));
	}
	return AuraAbilitySystemComponent;
}

void AAuraPlayerController::AutoRun()
{
	if (!bAutoRunning)
	{
		return;
	}
	if (APawn* ControlledPawn = GetPawn())
	{
		//由于无法确保角色位置和样条曲线百分之百重合在一块，所以我们先获取一下角色距离样条最近的位置
		const FVector LocationOnSpline = Spline->FindLocationClosestToWorldLocation(ControlledPawn->GetActorLocation(), ESplineCoordinateSpace::World);

		//然后通过此位置去获取在样条上的方向
		const FVector Direction = Spline->FindDirectionClosestToWorldLocation(LocationOnSpline, ESplineCoordinateSpace::World);
		
		// 将角色移动到样条曲线上
		ControlledPawn->AddMovementInput(Direction);

		//我们还需要在角色移动到终点时，设置它停止寻路，所以，我们还需要查询当前角色所在位置和终点位置的距离，如果小于我们设置的AutoRunAcceptanceRadius距离内，我们将停止自动寻路。
		const float DistanceToDestination = (LocationOnSpline - CachedDestination).Length();
		if(DistanceToDestination <= AutoRunAcceptanceRadius)
		{
			bAutoRunning = false;
		}

	}
}

void AAuraPlayerController::UpdateMagicCircleLocation() const
{
	if(IsValid(MagicCircle))
	{
		MagicCircle->SetActorLocation(CursorHit.ImpactPoint);
	}
}


void AAuraPlayerController::BeginPlay()
{
	Super::BeginPlay();
	check(AuraContext);// 确保在 AAuraPlayerController::BeginPlay 中调用了 Super::BeginPlay()

	// 获取本地玩家
	UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer());
	if(Subsystem)// 确保本地玩家存在
	{
		Subsystem->AddMappingContext(AuraContext, 0);// 将输入上下文添加到本地玩家
	}
	
	bShowMouseCursor = true;// 显示鼠标光标
	DefaultMouseCursor = EMouseCursor::Default;// 设置鼠标光标样式
	FInputModeGameAndUI InputModeData;// 创建输入模式数据
	InputModeData.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);//设置输入模式数据，使鼠标在视口中的行为为不锁定。
	InputModeData.SetHideCursorDuringCapture(false); //是否在鼠标按下导致的临时鼠标捕获期间隐藏光标
	SetInputMode(InputModeData);// 设置输入模式
	
}

void AAuraPlayerController::SetupInputComponent()
{
	Super::SetupInputComponent();

	
	UAuraInputComponent* AuraInputComponent = CastChecked<UAuraInputComponent>(InputComponent);
	
	AuraInputComponent->UAuraInputComponent::BindAbilityActions(InputConfig, this, &AAuraPlayerController::AbilityInputTagPressed,
											&AAuraPlayerController::AbilityInputTagReleased,&AAuraPlayerController::AbilityInputTagHeld);

	AuraInputComponent->BindAction(ShiftAction, ETriggerEvent::Started, this, &AAuraPlayerController::ShiftPressed);// 按下Shift
	AuraInputComponent->BindAction(ShiftAction, ETriggerEvent::Completed, this, &AAuraPlayerController::ShiftReleased);// 送下Shift
	AuraInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AAuraPlayerController::Move);
	// 绑定移动动作    Triggered 表示输入动作被触发时的事件，通常用于响应用户的输入操作。    回调调用Move


}

void AAuraPlayerController::ShowDamageNumber_Implementation(float DamageAmount, ACharacter* TargetCharacter, bool IsBlockedHit, bool IsCriticalHit)
{
	//确保传入的目标没被销毁并且设置了组件类
	if(IsValid(TargetCharacter) && DamageTextComponentClass &&IsLocalController())
	{
		UDamageTextComponent* DamageText = NewObject<UDamageTextComponent>(TargetCharacter, DamageTextComponentClass);
		DamageText->RegisterComponent(); //动态创建的组件需要调用注册
		DamageText->AttachToComponent(TargetCharacter->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform); //先附加到角色身上，使用角色位置
		DamageText->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); //然后从角色身上分离，保证在一个位置播放完成动画
		DamageText->SetDamageText(DamageAmount, IsBlockedHit, IsCriticalHit); //设置显示的伤害数字
	}
}


void AAuraPlayerController::Move(const FInputActionValue& InputActionValue)
{
	//通过标签阻止悬停事件的触发
	if(GetASC() && GetASC()->HasMatchingGameplayTag(FAuraGameplayTags::Get().Player_Block_InputPressed))
	{
		return;
	}
	const FVector2D InputAxisVector = InputActionValue.Get<FVector2D>();// 获取输入向量
	const FRotator Rotation = GetControlRotation();// 获取控制器旋转
	const FRotator YawRotation(0.f, Rotation.Yaw, 0.f);// 创建一个只包含 yaw 轴的旋转对象

	const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);// 获取前向方向
	const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);// 获取右方向

	if(APawn * ControlledPawn = GetPawn<APawn>())// 检查是否控制了某个 pawn
	{
		ControlledPawn->AddMovementInput(ForwardDirection, InputAxisVector.Y);
		ControlledPawn->AddMovementInput(RightDirection, InputAxisVector.X);
	}
}



